/*
     raw os - Copyright (C)  Lingjun Chen(jorya_txj).

    This file is part of raw os.

    raw os is free software; you can redistribute it it under the terms of the 
    GNU General Public License as published by the Free Software Foundation; 
    either version 3 of the License, or  (at your option) any later version.

    raw os is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
    without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program. if not, write email to jorya.txj@gmail.com
                                      ---

    A special exception to the LGPL can be applied should you wish to distribute
    a combined work that includes raw os, without being obliged to provide
    the source code for any proprietary components. See the file exception.txt
    for full details of how and when the exception can be applied.
*/


/* 	2012-7  Created by jorya_txj
  *	xxxxxx   please added here
  */


#include <raw_api.h>

#if (CONFIG_RAW_COND_MSG > 0)

/*
************************************************************************************************************************
*                                       Create a condition msg object
*
* Description: This service creates a condition msg object
*
* Arguments  :cond_msg_ptr is the address of condition msg object.
*                    -----
*                
*				         
*				         
* Returns   RAW_SUCCESS : create a condition msg object success.
*
* Note(s)    :
*
*             
************************************************************************************************************************
*/
RAW_U16 raw_cond_msg_create(RAW_COND_MSG *cond_msg_ptr)
{

	#if (RAW_COND_MSG_CHECK > 0)

    if (cond_msg_ptr == 0) {
			
        return RAW_NULL_POINTER;
    }
		
	#endif

	
	
	/*Init the list*/
	list_init(&cond_msg_ptr->common_block_obj.block_list);
	cond_msg_ptr->common_block_obj.block_way = RAW_BLOCKED_WAY_PRIO;
	cond_msg_ptr->common_block_obj.name = (RAW_U8 *)"raw_cond_msg";
	cond_msg_ptr->common_block_obj.object_type = RAW_CONDITION_OBJ_TYPE;
	
	return RAW_SUCCESS;

}

/*
************************************************************************************************************************
*                                      Wait a condition msg
*
* Description: Any task call this function will be blocked until the condition is set. And a message wiil be 
* received either when waken up.
*						
*					
*						
*
* Arguments  :cond_msg_ptr: is the address of condition msg object
*                    -----
*			wait_condition: is the condition variable to be waited for.It's range is from 1 to 255.
*                                           Be careful 0 is not allowed for wait_condition.
*			 -----
*                    msg: is the address of the message and will be filled in when condition is satisfied .
*                    -----
*			wait_option: is  how the service behaves if the selected
*			event flags are not set. The wait options are defined as follows:
*			                 		RAW_NO_WAIT (0x00000000)
*							RAW_WAIT_FOREVER (0xFFFFFFFF)
*							timeout value (0x00000001
*							through
*							0xFFFFFFFE)
*
* Returns   RAW_SUCCESS : Get event success.
*              RAW_BLOCK_ABORT: event is aborted by other task or ISR.
*              RAW_NO_PEND_WAIT: event is not got and option is RAW_NO_WAIT.
*              RAW_SCHED_DISABLE: system is locked ant task is not allowed block.
*              RAW_BLOCK_DEL: if this event is deleted
* Note(s)  :RAW_STATE_UNKNOWN wrong task state, probally sysytem error.
*              
*
*             
************************************************************************************************************************
*/
RAW_U16 raw_cond_msg_wait(RAW_COND_MSG *cond_msg_ptr, RAW_U8 wait_condition, RAW_U32 wait_option, RAW_VOID  **msg)
{
	RAW_U16 result;
	
	RAW_SR_ALLOC();
	
	#if (RAW_COND_MSG_CHECK > 0)

	if (cond_msg_ptr == 0) {
		
		return RAW_NULL_OBJECT;
	}
	

	if (raw_int_nesting) {

		return RAW_NOT_CALLED_BY_ISR;
		
	}

	if (msg == 0) {
		
		return RAW_NULL_POINTER;
	}
	
	#endif

	if (cond_msg_ptr->common_block_obj.object_type != RAW_CONDITION_OBJ_TYPE) {

		return RAW_ERROR_OBJECT_TYPE;
	}


	if (wait_condition == 0) {

		return RAW_NO_THIS_OPTION;

	}
	

	RAW_CRITICAL_ENTER();

	if (raw_task_active->raw_cond_msg_option == wait_condition) {
		
		RAW_CRITICAL_EXIT();
		return RAW_SUCCESS;
	}


	/*Cann't get condition msg, and return immediately if wait_option is  RAW_NO_WAIT*/
	if (wait_option == RAW_NO_WAIT) {
		*msg      = (RAW_VOID      *)0;
		RAW_CRITICAL_EXIT();	
		return RAW_NO_PEND_WAIT;
	}   
	
	/*system is locked so task can not be blocked just return immediately*/
	if (raw_sched_lock) {
		*msg      = (RAW_VOID      *)0;
		RAW_CRITICAL_EXIT();	
		return RAW_SCHED_DISABLE;
	}

	 /*Remember the passed information*/
	raw_task_active->raw_cond_msg_option =  wait_condition;

	raw_pend_object((RAW_COMMON_BLOCK_OBJECT  *)cond_msg_ptr, raw_task_active, wait_option);
	RAW_CRITICAL_EXIT();

	raw_sched(); 
	
	*msg      = (RAW_VOID      *)0;
	result = block_state_post_process(raw_task_active, msg);
	
	return result;

}


/*
************************************************************************************************************************
*                                      Set a condition msg
*
* Description: Wake up an blocked task if the condition is satisfied. If there is no blocked task, it simply returns  RAW_SUCCESS. 
*
*						
*					
*						
*
* Arguments  :cond_msg_ptr: is the address of condition msg object
*                    -----
*			 condition_set: is the condition variable to be set for.It's range is from 1 to 255.
*			 -----
*                    msg: is the address of the message and will be sent to blocked task when condition is satisfied .
*                    -----
*
*
* Returns  RAW_SUCCESS : Set an condition msg success.
*             RAW_NULL_OBJECT: Invalid pointer
*              
*             
*           
* Note(s)  :RAW_STATE_UNKNOWN wrong task state, probally sysytem error.
*              
*
*             
************************************************************************************************************************
*/
RAW_U16 raw_cond_msg_set(RAW_COND_MSG *cond_msg_ptr, RAW_U8 condition_set, RAW_VOID  *msg)
{
  
	LIST    									 *iter;
	LIST    									 *cond_msg_head_ptr;
	LIST 										 *iter_temp;
	struct RAW_TASK_OBJ          *task_ptr;
	
	RAW_U8 need_sche = 0;
	
	RAW_SR_ALLOC();

	#if (RAW_COND_MSG_CHECK > 0)

	if (cond_msg_ptr == 0) {
		
		return RAW_NULL_OBJECT;
	}
	
	#endif

	if (cond_msg_ptr->common_block_obj.object_type != RAW_CONDITION_OBJ_TYPE) {

		return RAW_ERROR_OBJECT_TYPE;
	}

	cond_msg_head_ptr = &cond_msg_ptr->common_block_obj.block_list;
	
	RAW_CRITICAL_ENTER();
	
	iter = cond_msg_head_ptr->next;

	/*if list is not empty*/
 	while (iter !=cond_msg_head_ptr) {

		task_ptr =  list_entry(iter, RAW_TASK_OBJ, task_list);
		iter_temp =  iter->next;
		
		if (task_ptr->raw_cond_msg_option  == condition_set)  {
		
			/*Ok the task condition is met, just wake this task*/
			wake_send_msg(task_ptr,  msg);	
			task_ptr->raw_cond_msg_option = 0;
	
			/*if  task is waken up*/
			need_sche = 1;
		}
		

		iter = iter_temp;

 	}

	RAW_CRITICAL_EXIT();

	if (need_sche) {
		
		do_possible_sche();
	}
	
	return RAW_SUCCESS;

}


/*
************************************************************************************************************************
*                                       Delete a condition msg object
*
* Description: This function is called to delete a condition msg object.
*
* Arguments  :cond_msg_ptr is the address of condition msg object.
*                
*                
*				         
* Returns		RAW_SUCCESS: raw os return success
* Note(s)    Any task pended on this condition msg object will be waked up and will return RAW_BLOCK_DEL.
*					
*
*             
************************************************************************************************************************
*/
#if (CONFIG_RAW_COND_MSG_DELETE > 0)
RAW_U16  raw_cond_msg_delete(RAW_COND_MSG *cond_msg_ptr)
{
	LIST *block_list_head;
	
   RAW_SR_ALLOC();
	 
	#if (RAW_COND_MSG_CHECK > 0)

	if (cond_msg_ptr == 0) {
		
		return RAW_NULL_OBJECT;
	}
		
	#endif

	if (cond_msg_ptr->common_block_obj.object_type != RAW_CONDITION_OBJ_TYPE) {

		return RAW_ERROR_OBJECT_TYPE;
	}

	block_list_head = &cond_msg_ptr->common_block_obj.block_list;
	
	RAW_CRITICAL_ENTER();
	cond_msg_ptr->common_block_obj.object_type = 0;
	/*All task blocked on this queue is waken up until list is empty*/
	while (!is_list_empty(block_list_head )) {
		delete_pend_obj(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list));	
	}    
	
	RAW_CRITICAL_EXIT();

    do_possible_sche();

	return RAW_SUCCESS;
}


#endif


#endif


